/*******************************************************************************
 * CopyRight (c) 2020 
 *
 * \file    mp4_output.c
 * \brief   output mp4 stream to file
 * \author  ZhangJing
 * \version 1.0.0
 * \date    2020-07-08
 *
 * -----------------------------------------------------------------------------
 * Modify history：
 * <Date>       | <Version> | <Author>  | <Discribe>
 * 2020-07-08   | v1.0.0    | ZhangJing | Create file
 * -----------------------------------------------------------------------------
 ******************************************************************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "publicdef.h"
#include "print_ctrl.h"
#include "format.h"

#define BUF_LEN (1024 * 1024 * 1)
static char buf[BUF_LEN];
static char obuf[BUF_LEN];

/*!
 * \brief write header of stream file with different stream type
 */ 
int mp4_write_header(void *format_context)
{
    //TODO: write header info if mp3 stream, similar to mp3enc.c
}

/*!
 * \brief write packet of stream file with different stream type
 */ 
int mp4_write_packet(void *format_context)
{
    FormatContext *fc = format_context;
    Stream *st = fc->streams[0];
    int i, j, k, l;
    Mp4Stream *ms = st->mp4st;
    IOContext *io = fc->io;
    int olen;
    //BUG:
    //IOContext *io_out = fc->io;
    //FIXME:
    FILE *fp = fopen(fc->ofname, "w+");

    pr_entry(in);

    /* get stream and write stream */
    l = 0;
    k = 0;
    if (ms->stsc_count > 1) { /* if use stsc, e.g. hevc/h265 */
        for (i = 0; i < ms->chunk_count;) {
            pr_debug("seek chunk[%d]", i + 1);
            io->io_seek(io, ms->chunk_offsets[i], SEEK_SET);
            if ((k + 1) < ms->stsc_count) { /* if not the final stsc_data */
                if (((i + 1) >= ms->stsc_data[k].first_chunk)
                    && (((i + 1) < ms->stsc_data[k + 1].first_chunk))) {
                    pr_debug("chunk ok[chunk%d-stscChunk%d]", i + 1, ms->stsc_data[k].first_chunk);
                    for (j = 0; j < ms->stsc_data[k].count_per_chunk; j++) {
                        olen = 0;
                        io->io_read(io, buf, ms->sample_sizes[l]);
                        if (st->bsf) {
                            st->bsf->filter(fc, buf, ms->sample_sizes[l], obuf, &olen);
                            //io_out->io_write(io_out, obuf, olen); //BUG:
                            fwrite(obuf, 1, olen, fp); //FIXME:
                        } else {
                            //io_out->io_write(io_out, buf, ms->sample_sizes[l]);
                            fwrite(buf, 1, ms->sample_sizes[l], fp);
                        }
                        l++;
                    }
                    pr_debug("chunk[%d] read ok, samples[%d]\n", i + 1, l);
                    i++;
                } else
                    k++;
            } else { /* is the final stsc_data */
                pr_debug("chunk ok[chunk%d-stscChunk%d]", i + 1, ms->stsc_data[k].first_chunk);
                for (j = 0; j < ms->stsc_data[k].count_per_chunk; j++) {
                    olen = 0;
                    io->io_read(io, buf, ms->sample_sizes[l]);
                    if (st->bsf) {
                        st->bsf->filter(fc, buf, ms->sample_sizes[l], obuf, &olen);
                        //io_out->io_write(io_out, obuf, olen);
                        fwrite(obuf, 1, olen, fp);
                    } else {
                        //io_out->io_write(io_out, buf, ms->sample_sizes[l]);
                        fwrite(buf, 1, ms->sample_sizes[l], fp);
                    }
                    l++;
                }
                pr_debug("chunk[%d] read ok, samples[%d]\n", i + 1, l);
                i++;
            }
        }
    } else { /* if not use stsc, e.g. h264 */
        for (l = 0; l < ms->chunk_count; l++) {
            olen = 0;
            io->io_seek(io, ms->chunk_offsets[l], SEEK_SET);
            io->io_read(io, buf, ms->sample_sizes[l]);
            if (st->bsf) {
                st->bsf->filter(fc, buf, ms->sample_sizes[l], obuf, &olen);
                //io_out->io_write(io_out, obuf, olen);
                fwrite(obuf, 1, olen, fp);
            } else {
                //io_out->io_write(io_out, buf, ms->sample_sizes[l]);
                fwrite(buf, 1, ms->sample_sizes[l], fp);
            }
        }
    }

//    fclose(fp);
}

/*!
 * \brief write header of stream file with different stream type
 */ 
int mp4_write_trailer(void *format_context)
{

}

OutputFormat mp4_output_format = {
    "mp4_output", ID_MP4,
    mp4_write_header, mp4_write_packet, mp4_write_trailer
};
